import logging
import os
from typing import Optional, List

import uvicorn
from apscheduler.schedulers.background import BackgroundScheduler
from fastapi import FastAPI, Form, UploadFile, File, HTTPException, Body
from starlette.responses import FileResponse

from reportagentic.config import SOURCE_DB_CONFIG, METADATA_DB_CONFIG, LLM_API_KEY, LLM_MODEL_NAME, \
    EMBEDDING_MODEL_NAME, VECTOR_STORAGE_PATH, LLM_API_BASE_URL, UPLOAD_DIRECTORY, GENERATED_REPORTS_DIR
from reportagentic.core.db import DatabaseConnector, MetadataRepository, TemplateRepository, QueryCacheRepository
from reportagentic.core.llm import LLMClient
from reportagentic.core.vector import VectorClient
from reportagentic.scheduler.template_scheduler import TemplateScheduler
from reportagentic.services.export_service import ExportService
from reportagentic.services.metadata_service import MetadataService
from reportagentic.services.template_service import TemplateService

app = FastAPI(title="报表导出系统 API", version="1.0")

template_repo = TemplateRepository(METADATA_DB_CONFIG)
meta_repo = MetadataRepository(METADATA_DB_CONFIG)
db_connector = DatabaseConnector(SOURCE_DB_CONFIG)
query_cache_repo = QueryCacheRepository(METADATA_DB_CONFIG)
llm_client = LLMClient(
    base_url=LLM_API_BASE_URL,
    api_key=LLM_API_KEY,
    chat_model=LLM_MODEL_NAME,
    embedding_model=EMBEDDING_MODEL_NAME
)
vector_client = VectorClient(storage_path=VECTOR_STORAGE_PATH)

template_service = TemplateService(
    template_repo=template_repo,
    meta_repo=meta_repo,
    llm_client=llm_client,
    vector_client=vector_client,
    upload_dir=UPLOAD_DIRECTORY
)

export_service = ExportService(
    vector_client=vector_client,
    llm_client=llm_client,
    meta_repo=meta_repo,
    template_repo=template_repo,
    query_cache_repo=query_cache_repo,
    source_db_connector=db_connector,
    reports_dir=GENERATED_REPORTS_DIR
)

template_Scheduler = TemplateScheduler(
    template_repo=template_repo,
    meta_repo=meta_repo,
    llm_client=llm_client,
    vector_client=vector_client,
)

logging.basicConfig(level=logging.INFO)

scheduler = BackgroundScheduler()
scheduler.add_job(template_Scheduler.sync_all_templates_to_vector_store, 'interval', minutes=1)
scheduler.start()


def init_metadata():
    """
    初始化所有组件并启动同步服务。
    """
    service = MetadataService(db_connector, llm_client, meta_repo, vector_client)
    service.run_sync()


@app.post("/report/template/upload", tags=["Template"])
async def upload_template(
        template_name: str = Form(..., description="报表模板的名称"),
        description: str = Form(..., description="对模板功能的详细描述"),
        template_file: UploadFile = File(..., description="定义报告列结构的基础模板文件"),
        example_descriptions: Optional[List[str]] = Form(None, description="【可选】描述该模板多种用途的纯文本示例列表")
):
    """
        注册一个报表模板，并自动执行“模板字段 -> 数据库列”的映射。

        - **不上传** 示例文件。
        - **不直接生成** SQL。
        - **核心功能**: LLM会分析模板表头和数据库Schema，自动创建并存储字段映射关系。
    """
    try:
        descriptions = example_descriptions if example_descriptions and example_descriptions[0] else None

        # 调用包含映射逻辑的新服务方法
        result = await template_service.register_template(
            template_name, description, template_file, descriptions
        )
        return {
            "status": "success",
            "message": "Template registered and fields mapped successfully.",
            "data": result
        }
    except ValueError as ve:
        # 这个异常现在也可能来自字段映射的失败
        raise HTTPException(status_code=400, detail=str(ve))
    except Exception as e:
        logging.error(f"An unexpected error occurred: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail="An internal server error occurred.")


# --- 用户导出流程 API ---
@app.post("/report/export/preview", tags=["Export"])
async def get_export_preview(payload: dict = Body(..., example={"query": "给我张三八月份的消费记录"})):
    """
    接收用户自然语言查询，返回数据预览和查询ID。
    """
    user_query = payload.get("query")
    if not user_query:
        raise HTTPException(status_code=400, detail="Query is required.")
    try:
        result = await export_service.generate_preview(user_query)
        return {"status": "success", "data": result}
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logging.error(f"Preview generation failed: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail="Failed to generate preview.")


@app.post("/report/export/download", tags=["Export"])
async def download_report(payload: dict = Body(..., example={"query_id": "some-uuid-string"})):
    """
    根据预览时获取的查询ID，生成并下载完整的报表文件。
    """
    query_id = payload.get("query_id")
    if not query_id:
        raise HTTPException(status_code=400, detail="Query ID is required.")
    try:
        file_path = await export_service.download_full_report(query_id)
        if not os.path.exists(file_path):
            raise HTTPException(status_code=404, detail="Generated file not found.")
        filename = os.path.basename(file_path)
        return FileResponse(
            path=file_path,
            media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            filename=filename,
            headers={
                'Content-Disposition': f'attachment; filename="{filename}"',
                'Cache-Control': 'no-cache'
            }
        )
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logging.error(f"Download failed: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail="Failed to generate final report.")


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
